winsafe\gui\native_controls/
tree_view_item.rs

1use std::any::TypeId;
2use std::cell::RefCell;
3use std::mem::ManuallyDrop;
4use std::rc::Rc;
5
6use crate::co;
7use crate::decl::*;
8use crate::gui::{iterators::*, *};
9use crate::kernel::privs::*;
10use crate::msg::*;
11use crate::prelude::*;
12
13/// A single item of a [`TreeView`](crate::gui::TreeView) control.
14///
15/// Each object keeps an unique [`HTREEITEM`](crate::HTREEITEM) handle.
16///
17/// You cannot directly instantiate this object, it is created internally by the
18/// control.
19pub struct TreeViewItem<'a, T: 'static = ()> {
20	owner: &'a TreeView<T>,
21	hitem: HTREEITEM,
22}
23
24impl<'a, T> Clone for TreeViewItem<'a, T> {
25	fn clone(&self) -> Self {
26		Self {
27			owner: self.owner,
28			hitem: unsafe { self.hitem.raw_copy() },
29		}
30	}
31}
32
33impl<'a, T> TreeViewItem<'a, T> {
34	#[must_use]
35	pub(in crate::gui) const fn new(owner: &'a TreeView<T>, hitem: HTREEITEM) -> Self {
36		Self { owner, hitem }
37	}
38
39	/// Adds a new child item by sending a
40	/// [`tvm::InsertItem`](crate::msg::tvm::InsertItem) message, and returns
41	/// the newly added item.
42	pub fn add_child(&self, text: &str, icon_index: Option<u32>, data: T) -> SysResult<Self> {
43		self.owner
44			.raw_insert_item(Some(&self.hitem), text, icon_index, data)
45	}
46
47	/// Returns a [`Rc`](std::rc::Rc)/[`RefCell`](std::cell::RefCell) with the
48	/// stored data by sending an [`lvm::GetItem`](crate::msg::lvm::GetItem)
49	/// message.
50	///
51	/// # Panics
52	///
53	/// Panics if the `TreeView` doesn't have an actual type, that is, if it was
54	/// declared as `TreeView<()>`.
55	///
56	/// Panics if the item index is invalid.
57	#[must_use]
58	pub fn data(&self) -> SysResult<Rc<RefCell<T>>> {
59		if TypeId::of::<T>() == TypeId::of::<()>() {
60			panic!("TreeView<()> will hold no data."); // user didn't define the generic type
61		}
62
63		let rc_ptr = self.data_lparam()?;
64		if rc_ptr.is_null() {
65			panic!("TreeViewItem with invalid index, no data.");
66		}
67
68		let rc_obj = ManuallyDrop::new(unsafe { Rc::from_raw(rc_ptr) });
69		Ok(Rc::clone(&rc_obj))
70	}
71
72	#[must_use]
73	pub(in crate::gui) fn data_lparam(&self) -> SysResult<*mut RefCell<T>> {
74		let mut tvix = TVITEMEX::default();
75		tvix.hItem = unsafe { self.hitem.raw_copy() };
76		tvix.mask = co::TVIF::PARAM;
77
78		unsafe {
79			self.owner
80				.hwnd()
81				.SendMessage(tvm::GetItem { tvitem: &mut tvix })?;
82		}
83
84		Ok(match tvix.lParam {
85			0 => std::ptr::null_mut(),
86			lp => lp as _,
87		})
88	}
89
90	/// Deletes the item by sending a
91	/// [`tvm::DeleteItem`](crate::msg::tvm::DeleteItem) message.
92	pub fn delete(&self) -> SysResult<()> {
93		unsafe {
94			self.owner
95				.hwnd()
96				.SendMessage(tvm::DeleteItem { hitem: &self.hitem })
97		}
98	}
99
100	/// Begins in-place editing of the item's text by sending a
101	/// [`tvm::EditLabel`](crate::msg::tvm::EditLabel) message.
102	///
103	/// Returns a handle to the edit control.
104	pub fn edit_label(&self) -> SysResult<HWND> {
105		unsafe {
106			self.owner
107				.hwnd()
108				.SendMessage(tvm::EditLabel { hitem: &self.hitem })
109		}
110	}
111
112	/// Ensures that a tree-view item is visible, expanding the parent item or
113	/// scrolling the tree-view control, if necessary, by sending a
114	/// [`tvm::EnsureVisible`](crate::msg::tvm::EnsureVisible) message.
115	///
116	/// Returns whether a scroll occurred and no items were expanded.
117	pub fn ensure_visible(&self) -> bool {
118		unsafe {
119			self.owner
120				.hwnd()
121				.SendMessage(tvm::EnsureVisible { hitem: &self.hitem })
122				!= 0
123		}
124	}
125
126	/// Expands or collapse the item by sending a
127	/// [`tvm::Expand`](crate::msg::tvm::Expand) message.
128	pub fn expand(&self, expand: bool) -> SysResult<()> {
129		unsafe {
130			self.owner.hwnd().SendMessage(tvm::Expand {
131				hitem: &self.hitem,
132				action: if expand { co::TVE::EXPAND } else { co::TVE::COLLAPSE },
133			})
134		}
135	}
136
137	/// Returns the underlying handle of the item.
138	#[must_use]
139	pub const fn htreeitem(&self) -> &HTREEITEM {
140		&self.hitem
141	}
142
143	/// Tells if the item is expanded by sending a
144	/// [`tvm::GetItemState`](crate::msg::tvm::GetItemState) message.
145	#[must_use]
146	pub fn is_expanded(&self) -> bool {
147		unsafe {
148			self.owner.hwnd().SendMessage(tvm::GetItemState {
149				hitem: &self.hitem,
150				mask: co::TVIS::EXPANDED,
151			})
152		}
153		.has(co::TVIS::EXPANDED)
154	}
155
156	/// Tells if the item is a root by sending a
157	/// [`tvm::GetNextItem`](crate::msg::tvm::GetNextItem) message.
158	#[must_use]
159	pub fn is_root(&self) -> bool {
160		self.parent().is_none()
161	}
162
163	/// Returns an iterator over the child items.
164	#[must_use]
165	pub fn iter_children(&self) -> impl Iterator<Item = TreeViewItem<'a, T>> + 'a {
166		TreeViewChildItemIter::new(self.owner, Some(self.clone()))
167	}
168
169	/// Returns an iterator over the next sibling items.
170	#[must_use]
171	pub fn iter_next_siblings(&self) -> impl Iterator<Item = TreeViewItem<'a, T>> + 'a {
172		TreeViewItemIter::new(self.owner, Some(self.clone()), co::TVGN::NEXT)
173	}
174
175	/// Returns an iterator over the previous sibling items.
176	#[must_use]
177	pub fn iter_prev_siblings(&self) -> impl Iterator<Item = TreeViewItem<'a, T>> + 'a {
178		TreeViewItemIter::new(self.owner, Some(self.clone()), co::TVGN::PREVIOUS)
179	}
180
181	/// Retrieves the parent of the item by sending a
182	/// [`tvm::GetNextItem`](crate::msg::tvm::GetNextItem) message.
183	#[must_use]
184	pub fn parent(&self) -> Option<Self> {
185		unsafe {
186			self.owner.hwnd().SendMessage(tvm::GetNextItem {
187				relationship: co::TVGN::PARENT,
188				hitem: Some(&self.hitem),
189			})
190		}
191		.map(|hitem| TreeViewItem::new(self.owner, hitem))
192	}
193
194	/// Sets the text of the item by sending a
195	/// [`tvm::SetItem`](crate::msg::tvm::SetItem) message.
196	pub fn set_text(&self, text: &str) -> SysResult<()> {
197		let mut buf = WString::from_str(text);
198
199		let mut tvix = TVITEMEX::default();
200		tvix.hItem = unsafe { self.hitem.raw_copy() };
201		tvix.mask = co::TVIF::TEXT;
202		tvix.set_pszText(Some(&mut buf));
203
204		unsafe {
205			self.owner
206				.hwnd()
207				.SendMessage(tvm::SetItem { tvitem: &tvix })
208		}
209	}
210
211	/// Retrieves the text of the item by sending a
212	/// [`tvm::GetItem`](crate::msg::tvm::GetItem) message.
213	#[must_use]
214	pub fn text(&self) -> SysResult<String> {
215		let mut tvix = TVITEMEX::default();
216		tvix.hItem = unsafe { self.hitem.raw_copy() };
217		tvix.mask = co::TVIF::TEXT;
218
219		let mut buf = WString::new_alloc_buf(MAX_PATH + 1); // arbitrary
220		tvix.set_pszText(Some(&mut buf));
221
222		unsafe {
223			self.owner
224				.hwnd()
225				.SendMessage(tvm::GetItem { tvitem: &mut tvix })?;
226		}
227
228		Ok(buf.to_string())
229	}
230}